package com.jsmile.cloud.msgcenter.zf.kit;

import java.util.Map;

import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.Feature;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipayEncrypt;
import com.alipay.api.internal.util.AlipaySignature;
import com.google.common.base.Strings;
import com.jsmile.cloud.msgcenter.api.exception.MsgException;
import com.jsmile.cloud.msgcenter.web.config.PayConfig;
import com.jsmile.cloud.msgcenter.zf.req.ali.AliPayInfo;

import jodd.exception.ExceptionUtil;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class AliDecodeKit {

    private static final String MINI_PROGRAM = "mini";

    public <T> T decode(String appId, String response, TypeReference<T> typeReference, boolean needCheckSign) throws Exception {

        // 1. 获取验签和解密所需要的参数
        Map<String, String> openapiResult = JSON.parseObject(response, new TypeReference<Map<String, String>>() {}, Feature.OrderedField);
        String sign = openapiResult.get("sign");
        String content = openapiResult.get("response");

        // 如果密文的
        boolean isDataEncrypted = !content.startsWith("{");
        boolean signCheckPass = false;

        // 2. 验签
        AliPayInfo aliPayInfo = PayConfig.getAliService(appId);

        // 你的小程序对应的加解密密钥（为扩展考虑建议用appId+encryptType做密钥存储隔离）
        String decryptKey = aliPayInfo.getAesKey();

        log.info("signContent:{};\n\ndecryptKey:{}", content, decryptKey);
        if (needCheckSign) {
            checkSign(openapiResult, aliPayInfo);
        }

        // 3. 解密
        String plainData;
        if (isDataEncrypted) {
            try {
                plainData = AlipayEncrypt.decryptContent(content, aliPayInfo.getEncryptType(), decryptKey, aliPayInfo.getCharset());
            } catch (AlipayApiException e) {
                // 解密异常, 记录日志
                e.printStackTrace();
                throw new Exception("解密异常");
            }
        } else {
            plainData = content;
        }
        return JSON.parseObject(plainData, typeReference);
    }

    /**
     * 该验签方式为异步通知验签，生活号验签需另外重写
     *
     * @param response
     * @param aliPayInfo
     * @return
     */
    public boolean checkSign(String response, AliPayInfo aliPayInfo) {
        // 1. 获取验签和解密所需要的参数
        Map<String, String> openapiResult = JSON.parseObject(response, new TypeReference<Map<String, String>>() {}, Feature.OrderedField);
        return checkSign(openapiResult, aliPayInfo);
    }

    public boolean checkSign(Map<String, String> openapiResult, AliPayInfo aliPayInfo) {
        boolean signCheckPass = false;
        try {
            // 你的小程序对应的支付宝公钥（为扩展考虑建议用appId+signType做密钥存储隔离）
            String signVeriKey = aliPayInfo.getAlipayPublicKey();
            if (Strings.isNullOrEmpty(signVeriKey)) {
                throw new MsgException("找不到支付宝公钥,验签失败");
            }
            log.info("signVeriKey:{};", signVeriKey);
            signCheckPass = AlipaySignature.rsaCheckV1(openapiResult, signVeriKey, aliPayInfo.getCharset(), aliPayInfo.getSignType());
        } catch (AlipayApiException e) {
            // 验签异常, 日志
            log.error("验签异常----{}", ExceptionUtil.exceptionStackTraceToString(e));
        }
        if (!signCheckPass) {
            // 验签不通过（异常或者报文被篡改），终止流程（不需要做解密）
            throw new MsgException("验签失败");
        }
        return Boolean.TRUE;
    }

}
